package net.mikoo.seals.biz.service.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;

import net.mikoo.seals.biz.common.BaseServices;
import net.mikoo.seals.biz.manager.DevicesUsedManager;
import net.mikoo.seals.biz.manager.WechatManager;
import net.mikoo.seals.biz.manager.WorkflowManager;
import net.mikoo.seals.biz.mapper.CompanyMapper;
import net.mikoo.seals.biz.mapper.CustosMapper;
import net.mikoo.seals.biz.mapper.DevicesActMapper;
import net.mikoo.seals.biz.mapper.DevicesMapper;
import net.mikoo.seals.biz.mapper.DevicesTakeMapper;
import net.mikoo.seals.biz.mapper.DevicesUsedCertMapper;
import net.mikoo.seals.biz.mapper.DevicesUsedCertUpfileMapper;
import net.mikoo.seals.biz.mapper.DevicesUsedFailMapper;
import net.mikoo.seals.biz.mapper.DevicesUsedMapper;
import net.mikoo.seals.biz.mapper.InstallMapper;
import net.mikoo.seals.biz.mapper.PartyMapper;
import net.mikoo.seals.biz.mapper.SealMapper;
import net.mikoo.seals.biz.mapper.StaffMapper;
import net.mikoo.seals.biz.mapper.UpfileMapper;
import net.mikoo.seals.biz.mapper.UserLoginMapper;
import net.mikoo.seals.biz.mapper.WorkflowMapper;
import net.mikoo.seals.biz.service.DevicesServices;
import net.mikoo.seals.common.enums.ApplyTypeEnum;
import net.mikoo.seals.common.enums.CensorStatusEnum;
import net.mikoo.seals.common.enums.CertUploadStatusEnum;
import net.mikoo.seals.common.enums.CustosStatusEnum;
import net.mikoo.seals.common.enums.CustosTypeEnum;
import net.mikoo.seals.common.enums.DevicesStatusEnum;
import net.mikoo.seals.common.enums.InstallStatusEnum;
import net.mikoo.seals.common.enums.InstallTypeEnum;
import net.mikoo.seals.common.enums.SealStatusEnum;
import net.mikoo.seals.common.enums.TakeStatusEnum;
import net.mikoo.seals.common.enums.UsedStatusEnum;
import net.mikoo.seals.common.exception.DataNotFoundException;
import net.mikoo.seals.common.exception.ParametersException;
import net.mikoo.seals.common.model.PageModel;
import net.mikoo.seals.model.Company;
import net.mikoo.seals.model.Custos;
import net.mikoo.seals.model.CustosQuery;
import net.mikoo.seals.model.Devices;
import net.mikoo.seals.model.DevicesAct;
import net.mikoo.seals.model.DevicesActQuery;
import net.mikoo.seals.model.DevicesQuery;
import net.mikoo.seals.model.DevicesTake;
import net.mikoo.seals.model.DevicesTakeQuery;
import net.mikoo.seals.model.DevicesUsed;
import net.mikoo.seals.model.DevicesUsedCert;
import net.mikoo.seals.model.DevicesUsedCertQuery;
import net.mikoo.seals.model.DevicesUsedCertUpfile;
import net.mikoo.seals.model.DevicesUsedFail;
import net.mikoo.seals.model.DevicesUsedQuery;
import net.mikoo.seals.model.Install;
import net.mikoo.seals.model.InstallQuery;
import net.mikoo.seals.model.Party;
import net.mikoo.seals.model.Seal;
import net.mikoo.seals.model.Staff;
import net.mikoo.seals.model.StaffQuery;
import net.mikoo.seals.model.Upfile;
import net.mikoo.seals.model.UserLogin;
import net.mikoo.seals.model.Workflow;

public class DevicesServicesImpl extends BaseServices implements DevicesServices {
	
	private Logger logger = LoggerFactory.getLogger(DevicesServicesImpl.class);

	@Autowired
	private DevicesMapper devicesMapper;
	
	@Autowired
	private DevicesActMapper devicesActMapper;
	
	@Autowired
	private CustosMapper custosMapper;
	
	@Autowired
	private PartyMapper partyMapper;
	
	@Autowired
	private CompanyMapper companyMapper;
	
	@Autowired
	private WorkflowMapper workflowMapper;
	
	@Autowired
	private DevicesUsedMapper devicesUsedMapper;
	
	@Autowired
	private DevicesUsedManager devicesUsedManager;
	
	@Autowired
	private DevicesUsedCertMapper devicesUsedCertMapper;
	
	@Autowired
	private DevicesUsedCertUpfileMapper devicesUsedCertUpfileMapper;
	
	@Autowired
	private SealMapper sealMapper;
	
	
	@Autowired
	private UpfileMapper upfileMapper;
	
	@Autowired
	private DevicesTakeMapper devicesTakeMapper;
	
	@Autowired
	private UserLoginMapper userLoginMapper;
	
	@Autowired
	private StaffMapper staffMapper;
	
	
	@Autowired
	private DevicesUsedFailMapper devicesUsedFailMapper;
	
	@Autowired
	private WorkflowManager workflowManager;
	
	@Autowired
	private WechatManager wechatManager;
	
	@Autowired
	private InstallMapper installMapper;
	
	@Override
	public PageModel<Devices> getPageByQuery(DevicesQuery query) {
		List<Devices> datas = devicesMapper.selectByQueryToPage(query);
		Integer total = devicesMapper.countByQueryToPage(query);
		PageModel<Devices> pm = new PageModel<Devices>(total,datas);
		return pm;
	}
	
	@Override
	public Devices getInfoById(Long devicesId) {
		if(devicesId == null) {
			throw new ParametersException("devicesId");
		}
		Devices devices = devicesMapper.selectInfoById(devicesId);
		return devices;
	}
	
	
	
	@Override
	public List<Devices> getListByQuery(DevicesQuery query) {
		
		if(query == null) {
			throw new ParametersException("参数错误");
		}
		
		return devicesMapper.selectListByQuery(query);
	}

	@Override
	public void save(Devices devices) {
		
		if(devices == null) {
			throw new ParametersException("devices");
		}
		
		if(StringUtils.isBlank(devices.getDevicesCode())) {
			throw new ParametersException("devicesCode");
		}
		
		if(devices.getSealId() == null) {
			throw new ParametersException("SealId");
		}
		
		if(StringUtils.isBlank(devices.getModel())) {
			throw new ParametersException("model");
		}
		
		if(devices.getCompanyId() == null) {
			throw new ParametersException("companyId");
		}
		
		if(devices.getProduceDate() == null) {
			throw new ParametersException("ProduceDate");
		}
		
		if(devices.getExpireDate() == null) {
			throw new ParametersException("ExpireDate");
		}
		
		Seal seal = sealMapper.selectInfoById(devices.getSealId());
		if(seal == null) {
			throw new ParametersException("印章不存在");
		}
		
		Company company = companyMapper.selectInfoById(devices.getCompanyId());
		if(company == null) {
			throw new ParametersException("公司不存在");
		}
		
		devices.setCreateTime(new Date());
		devices.setUseTimes(0);
		devices.setApplyTimes(0);
		devices.setIsActivate("N");
		devices.setDevicesStatus(DevicesStatusEnum.WAIT_INSTALL.getCode());
		devices.setVersion(0);
		devicesMapper.insert(devices);
	}

	@Override
	public void install(Long devicesId, Long companyId, String userLoginId) {
		if(devicesId == null) {
			throw new IllegalArgumentException("devicesId");
		}
		
		if(companyId == null) {
			throw new IllegalArgumentException("companyId");
		}
		
		Devices devices = devicesMapper.selectInfoById(devicesId);
		if(devices == null) {
			throw new RuntimeException("db not exist devicesId is 【" + devicesId + "】 record");
		}
		
		if(!DevicesStatusEnum.INSTALL_VERIFY.getCode().equals(devices.getDevicesStatus()) && 
				!DevicesStatusEnum.RESET_INSTALL_VERIFY.getCode().equals(devices.getDevicesStatus())) {
			throw new RuntimeException("devices status not is waitinstall");
		}
		
		if(!companyId.equals(devices.getCompanyId())) {
			throw new RuntimeException("devices not is the company");
		}
		
		if(!isCompanyAdmin(devices.getCompanyId(), userLoginId) && !isSealCustos(devices.getSealId(), userLoginId)) {
			throw new ParametersException("当前用户不是公司管理员，不能进行此操作");
		}
	}
	
	@Override
	public void installConfirm(Devices devices, String userLoginId) {
		if(devices == null) {
			throw new ParametersException("参数传入错误");
		}
		
		if(devices.getDevicesId() == null) {
			throw new ParametersException("参数传入错误");
		}
		
		if(devices.getCompanyId() == null) {
			throw new ParametersException("参数传入错误");
		}

		Devices exist = devicesMapper.selectInfoById(devices.getDevicesId());
		
		if(exist == null) {
			throw new ParametersException("设备不存在");
		}
		
		if(!DevicesStatusEnum.INSTALL_VERIFY.getCode().equals(exist.getDevicesStatus()) && 
				!DevicesStatusEnum.RESET_INSTALL_VERIFY.getCode().equals(exist.getDevicesStatus())) {
			throw new ParametersException("设备状态异常");
		}
		
		if(!exist.getCompanyId().equals(devices.getCompanyId())) {
			throw new ParametersException("您无权操作此设备");
		}
		
		if(!isCompanyAdmin(exist.getCompanyId(), userLoginId) && !isSealCustos(exist.getSealId(), userLoginId)) {
			throw new ParametersException("当前用户不是公司管理员或印章管理员，不能进行此操作");
		}
		
		exist.setDevicesStatus(DevicesStatusEnum.ACTIVATE.code());
		exist.setInstallTime(new Date());
		devicesMapper.update(exist);
	}
	
	@Override
	public void resetStatus(Long devicesId, String userLoginId) {
		
		if(devicesId == null) {
			throw new ParametersException("devicesId");
		}
		
		if(StringUtils.isBlank(userLoginId)){
			throw new ParametersException("userLoginId");
		}
		
		Devices devices = devicesMapper.selectInfoById(devicesId);
		if(devices == null) {
			throw new ParametersException("设备不存在");
		}
		
		DevicesStatusEnum status = DevicesStatusEnum.getByCode(devices.getDevicesStatus());
		if(status != DevicesStatusEnum.WAIT_TEST && 
				status != DevicesStatusEnum.WAIT_UPLOAD_VOUCHER && 
				status != DevicesStatusEnum.WAIT_ACTIVATE && 
				status != DevicesStatusEnum.RESET_INSTALL_VERIFY && 
				status != DevicesStatusEnum.ACTIVATE) {
			throw new ParametersException("设备状态不是已安装，无法重新安装");
		}
		
		if(!isCompanyAdmin(devices.getCompanyId(), userLoginId) && !isSealCustos(devices.getSealId(), userLoginId)) {
			throw new ParametersException("不是系统管理员或印章管理员，无权重新安装");
		}
		
		devices.setDevicesStatus(DevicesStatusEnum.INSTALL_VERIFY.getCode());
		devicesMapper.update(devices);
	}

	@Override
	public void setWorkflow(Long devicesId, Long workflowId, Long companyId, String userLoginId) {
		if(devicesId == null) {
			throw new IllegalArgumentException("devicesId");
		}
		
		if(workflowId == null) {
			throw new IllegalArgumentException("devicesId");
		}
		
		if(companyId == null) {
			throw new IllegalArgumentException("companyId");
		}
		
		Devices devices = devicesMapper.selectInfoById(devicesId);
		if(devices == null) {
			throw new RuntimeException("devices is not exist");
		}
		
		if(!companyId.equals(devices.getCompanyId())) {
			throw new RuntimeException("devices companyId is not match");
		}
		
		if(!DevicesStatusEnum.WAIT_TEST.getCode().equals(devices.getDevicesStatus())) {
			throw new RuntimeException("devices status not is INSTALLED");
		}
		
		if(!isCompanyAdmin(devices.getCompanyId(), userLoginId) && !isSealCustos(devices.getSealId(), userLoginId)) {
			throw new ParametersException("当前用户不是公司管理员或印章管理员，不能进行此操作");
		}
		
		Workflow workflow = workflowMapper.selectInfoById(workflowId);
		if(workflow == null) {
			throw new RuntimeException("workflow is not exist");
		}
		
		if(!companyId.equals(workflow.getCompanyId())) {
			throw new RuntimeException("workflow companyId is not match");
		}
		
		devices.setWorkflowId(workflowId);
		devicesMapper.update(devices);
	}

	@Override
	public void setCustos(Long sealId, Long partyId, String userLoginId) {
		
		if(sealId == null) {
			throw new IllegalArgumentException("sealId");
		}
		
		if(partyId == null) {
			throw new IllegalArgumentException("partyId");
		}
		
		Seal seal = sealMapper.selectInfoById(sealId);
		if(seal == null) {
			throw new IllegalStateException("seal not exist");
		}
		
		if(partyId.equals(seal.getPartyId())) {
			return ;
		}
		
		Party party = partyMapper.selectByPrimaryKey(partyId);
		if(party == null) {
			throw new IllegalStateException("party not exist");
		}
		
		DevicesQuery query = new DevicesQuery();
		query.setSealId(sealId);
		Devices devices = devicesMapper.selectInfoByQuery(query);
		
		if(devices == null) {
			throw new IllegalStateException("devices not exist");
		}
		
//		if(!isCompanyAdmin(devices.getCompanyId(), userLoginId)) {
//			throw new ParametersException("当前用户不是公司管理员，不能进行此操作");
//		}
		
		seal.setPartyId(partyId);
		seal.setCustosName(party.getPerson().getName());
		sealMapper.update(seal);
	}

	@Override
	public void publish(Devices devices, String userLoginId) {
		
		if(devices == null) {
			throw new IllegalArgumentException("devices");
		}
		
		if(devices.getDevicesId() == null) {
			throw new IllegalArgumentException("devices.devicesId");
		}
		
		if(devices.getCompanyId() == null) {
			throw new IllegalArgumentException("devices.companyId");
		}
		
		Devices exist = devicesMapper.selectInfoById(devices.getDevicesId());
		
		if(exist == null) {
			throw new IllegalStateException("设备不存在");
		}
		
		if(!exist.getDevicesStatus().equals(DevicesStatusEnum.WAIT_ACTIVATE.code())) {
			throw new IllegalStateException("设备状态不是WAIT_ACTIVATE");
		}
		
		if(exist.getSeal() == null || exist.getSeal().getSealId() == null) {
			throw new IllegalStateException("数据错误");
		}
		
		if(!exist.getCompanyId().equals(devices.getCompanyId())) {
			throw new ParametersException("您无权操作此设备");
		}
		
		if(!isCompanyAdmin(exist.getCompanyId(), userLoginId) && !isSealCustos(exist.getSealId(), userLoginId)) {
			throw new ParametersException("当前用户不是公司管理员或印章管理员，不能进行此操作");
		}
		
		CustosQuery custosQuery = new CustosQuery();
		custosQuery.setDevicesId(devices.getDevicesId());
		custosQuery.setCompanyId(devices.getCompanyId());
		
		
		DevicesUsedQuery usedQuery = new DevicesUsedQuery();
		usedQuery.setDevicesId(devices.getDevicesId());
		usedQuery.setCompanyId(devices.getCompanyId());
		usedQuery.setApplyType(ApplyTypeEnum.TEST_APPLY.code());
		
		List<DevicesUsed> list = devicesUsedMapper.selectListByQuery(usedQuery);
		if(list == null || list.isEmpty()) {
			throw new ParametersException("设备安装后还未测试，请先测试后再发布");
		}
		
		exist.setDevicesStatus(DevicesStatusEnum.ACTIVATE.code());
		
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				try {
					devicesMapper.update(exist);
					Seal seal = exist.getSeal();
					seal.setSealStatus(SealStatusEnum.ENABLE.getCode());
					sealMapper.updateStatus(seal);
				}catch(Exception e) {
					status.setRollbackOnly();
					logger.error("", e);
					throw new IllegalStateException("保存数据失败");
				}
			}
		});
	}

	@Override
	public List<DevicesAct> getValidActListByQuery(DevicesActQuery query) {
		
		List<DevicesAct> acts =  devicesActMapper.selectListByQuery(query);
		
		return acts;
	}

	@Override
	public void setting(Seal seal) {
		
		if(seal == null){
			throw new ParametersException("seal is null!");
		}
		
		if(seal.getDevicesId() == null) {
			throw new ParametersException("DevicesId is null");
		}
		
		if(StringUtils.isBlank(seal.getSealName())) {
			throw new ParametersException("印章名称不能为空");
		}
		
		if(seal.getPartyId() == null) {
			throw new ParametersException("印章管理员不能为空");
		}
		
		if(seal.getCompanyId() == null) {
			throw new ParametersException("印章管理员不能为空");
		}
		
		if(seal.getLimitUrgentApply() == null) {
			throw new ParametersException("请输入紧急申请次数");
		}
		
		if(StringUtils.isBlank(seal.getVerifyPartyIds())) {
			throw new ParametersException("请选择审核人员");
		}
		
		if(StringUtils.isBlank(seal.getIsForcedPhoto())) {
			seal.setIsForcedPhoto("N");
		}
		
		if(StringUtils.isNotBlank(seal.getUseSpecial())) {
			seal.setUseSpecial("Y");
		}else {
			seal.setUseSpecial("N");
		}
		
		
		
		Party party = partyMapper.selectByPrimaryKey(seal.getPartyId());
		if(party == null) {
			throw new ParametersException("保管员信息不存在");
		}
		
		StaffQuery query = new StaffQuery();
		query.setCompanyId(seal.getCompanyId());
		query.setPartyId(seal.getPartyId());
		Staff staff = staffMapper.selectInfoByQuery(query);
		if(staff == null) {
			throw new ParametersException("保管员不是公司员工，无法设置");
		}
		
		
		
		
		DevicesQuery devicesQuery = new DevicesQuery();
		devicesQuery.setCompanyId(seal.getCompanyId());
		devicesQuery.setDevicesId(seal.getDevicesId());
		Devices devices = devicesMapper.selectInfoByQuery(devicesQuery);
		if(devices == null) {
			throw new ParametersException("设备不存在");
		}
		
		this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				try {
					
					if(devices.getSealId() == null) {
						
						//创建工作流
						Workflow workflow = workflowManager.analyze(seal);
						Workflow special = workflowManager.special(seal);
						if(special == null) {
							seal.setSpecialWorkflowId(null);
						}else {
							seal.setSpecialWorkflowId(special.getWorkflowId());
						}
						
						
						seal.setCustosName(party.getPerson().getName());
						seal.setQuantity(0);
						seal.setApplyTimes(0);
						seal.setUseTimes(0);
						seal.setSealStatus(SealStatusEnum.ENABLE.getCode());
						seal.setCreateTime(new Date());
						seal.setWorkflowId(workflow.getWorkflowId());
						
						sealMapper.insert(seal);
						
						devices.setDevicesStatus(DevicesStatusEnum.WAIT_INSTALL.code());
						devices.setSealId(seal.getSealId());
						devicesMapper.update(devices);
						
						Custos custos = new Custos();
						custos.setCompanyId(seal.getCompanyId());
						custos.setCustosType(CustosTypeEnum.CUSTOS.code());
						custos.setSealId(seal.getSealId());
						custos.setDevicesId(devices.getDevicesId());
						custos.setPartyId(seal.getPartyId());
						custos.setUserLoginId(party.getUserLoginId());
						custos.setCreateTime(new Date());
						custos.setCustosStatus(CustosStatusEnum.EFFECTIVE.code());
						custos.setRemark("系统管理员设置为保管员");
						custosMapper.insert(custos);
					}else {
						
						
						//解析并且添加
						workflowManager.analyze(seal);
						Workflow special = workflowManager.special(seal);
						if(special == null) {
							seal.setSpecialWorkflowId(null);
						}else {
							seal.setSpecialWorkflowId(special.getWorkflowId());
						}
						seal.setCustosName(party.getPerson().getName());
						sealMapper.update(seal);
						
						Custos exits = custosMapper.selectInfoByQuery(new CustosQuery(seal.getCompanyId(),seal.getSealId(),seal.getDevicesId(),CustosStatusEnum.EFFECTIVE.code(),CustosTypeEnum.CUSTOS.code()));
						if(exits != null && !exits.getPartyId().equals(seal.getSealId())) {
							exits.setCustosStatus(CustosStatusEnum.INVALID.code());
							exits.setRemark("系统管理员重置保管员失效");
							custosMapper.update(exits);
						}
						Custos custos = new Custos();
						custos.setCompanyId(seal.getCompanyId());
						custos.setCustosType(CustosTypeEnum.CUSTOS.code());
						custos.setSealId(seal.getSealId());
						custos.setDevicesId(devices.getDevicesId());
						custos.setPartyId(seal.getPartyId());
						custos.setUserLoginId(party.getUserLoginId());
						custos.setCreateTime(new Date());
						custos.setCustosStatus(CustosStatusEnum.EFFECTIVE.code());
						custos.setRemark("系统管理员设置为保管员");
						custosMapper.insert(custos);
						
					}
				} catch (Exception e) {
					status.setRollbackOnly();
					throw e;
				}
			}
		});
	}

	@Override
	public void used(DevicesUsed used) {
		devicesUsedManager.checkParams(used);
		
		//1.扣除设备可用记录
		DevicesActQuery query  = new DevicesActQuery();
		query.setCompanyId(used.getCompanyId());
		query.setPartyId(used.getPartyId());
		query.setDevicesActId(used.getDevicesActId());
		
		DevicesAct devicesAct = devicesActMapper.selectInfoByQuery(query);
		if(devicesAct == null) {
			throw new DataNotFoundException("待使用记录未发现");
		}
		
		if(devicesAct.getTotalTimes() <= devicesAct.getUseTimes()) {
			throw new ParametersException("无可用次数，请申请");
		}
		
		Devices devices = devicesMapper.selectInfoById(used.getDevicesId());
		if(devices == null) {
			throw new ParametersException("使用的印章不存在");
		}
		
		devicesAct.setUseTimes(devicesAct.getUseTimes() + 1);
		devicesAct.setUsedStatus(UsedStatusEnum.WAIT_UPLOAD_CERT.getCode());
		
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				try {
					
					Integer num = devicesActMapper.update(devicesAct);
					if(num == null || num == 0) {
						throw new ParametersException("使用超时，请重试");
					}
					
					//2.添加使用记录
					used.setUsedTime(new Date());
					used.setUsedStatus(UsedStatusEnum.WAIT_UPLOAD_CERT.code());
					used.setApplyId(devicesAct.getApplyId());
					used.setApplyType(devicesAct.getApplyType());
					used.setApplyTime(devicesAct.getApplyTime());
					used.setCertUploadStatus("WAIT_UPLOAD");
					used.setSealId(devices.getSealId());
					devicesUsedMapper.insert(used);
					
					devices.setUseTimes(devices.getUseTimes() + 1);
					DevicesStatusEnum devicesStatus = DevicesStatusEnum.getByCode(devices.getDevicesStatus());
					if(devicesStatus == DevicesStatusEnum.WAIT_TEST) {
						devices.setDevicesStatus(DevicesStatusEnum.WAIT_UPLOAD_VOUCHER.code());
					}
					devicesMapper.update(devices);
				}catch (ParametersException e) {
					logger.error("",e);
					status.setRollbackOnly();
					throw e;
				}catch (Exception e) {
					logger.error("",e);
					status.setRollbackOnly();
					throw e;
				}
			}
		});
	}
	
	@Override
	public void rollBackUse(DevicesUsedFail fail, Integer times) {
		
		if(fail == null) {
			throw new IllegalArgumentException("fail");
		}
		
		if(fail.getDevicesActId() == null) {
			throw new IllegalArgumentException("devicesUsedId");
		}
		
		DevicesAct devicesAct = devicesActMapper.selectInfoById(fail.getDevicesActId());
		if(devicesAct == null) {
			throw new IllegalStateException("devicesUsed not exist");
		}
		
		Devices devices = devicesMapper.selectInfoById(devicesAct.getDevicesId());
		if(devices == null) {
			throw new IllegalStateException("devices not exist");
		}
		
		if(times != null) {
			fail.setCause(fail.getCause() + times + "次");
			fail.setTimes(times);
		}
		
		fail.setDevicesActId(devicesAct.getDevicesActId());
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			@Override
			public void doInTransactionWithoutResult(TransactionStatus status) {
				try {
					devicesUsedFailMapper.insert(fail);
				}catch(Exception e) {
					status.setRollbackOnly();
					throw e;
				}
			}
		});
		
		Seal seal = sealMapper.selectInfoById(devices.getSealId());
		if(seal != null && times != null) {
			wechatManager.aberrant(seal.getSealName(), "异常使用" + times + "次", seal.getPartyId());
		}
	}

	@Override
	public void setUsedImg(DevicesUsedCert devicesUsedCert) {
		
		if(devicesUsedCert == null) {
			throw new ParametersException("devicesUsedCer");
		}
		
		if(devicesUsedCert.getDevicesActId() == null) {
			throw new ParametersException("devicesUsedCer.DevicesActId");
		}
		
		if(devicesUsedCert.getDevicesUsedCertUpfiles() == null || devicesUsedCert.getDevicesUsedCertUpfiles().isEmpty()) {
			throw new ParametersException("devicesUsedCer.DevicesUsedCerUpfiles");
		}
		
		devicesUsedCert.setCertTotal(devicesUsedCert.getDevicesUsedCertUpfiles().size());
		devicesUsedCert.setCertStatus("UPLOAD");
		devicesUsedCert.setCreateTime(new Date());
		
		DevicesAct devicesAct = devicesActMapper.selectInfoById(devicesUsedCert.getDevicesActId());
		if(devicesAct == null) {
			throw new IllegalArgumentException("使用记录不存");
		}
		
		UsedStatusEnum status = UsedStatusEnum.getByCode(devicesAct.getUsedStatus());
		if(status == UsedStatusEnum.WAIT_UPLOAD_CERT) {
			Upfile upfile = upfileMapper.selectInfoById(devicesUsedCert.getDevicesUsedCertUpfiles().get(0).getUpfileId());
			
			if(upfile == null) {
				throw new DataNotFoundException("上传的凭证不存在");
			}
			
			Devices devices = devicesMapper.selectInfoById(devicesAct.getDevicesId());
			if(devices == null) {
				throw new DataNotFoundException("设备不存在");
			}
			
			transactionTemplate.execute(new TransactionCallback<Boolean>() {
				@Override
				public Boolean doInTransaction(TransactionStatus status) {
					try {
						devicesUsedCertMapper.insert(devicesUsedCert);
						for(int i = 0 ; i < devicesUsedCert.getDevicesUsedCertUpfiles().size(); i++) {
							DevicesUsedCertUpfile upfile = devicesUsedCert.getDevicesUsedCertUpfiles().get(i);
							upfile.setDevicesUsedCertId(devicesUsedCert.getDevicesUsedCertId());
							upfile.setSequence(i);
							upfile.setCreateTime(new Date());
							devicesUsedCertUpfileMapper.insert(upfile);
						}
						
						devicesAct.setUsedStatus(UsedStatusEnum.SUCCESS.getCode());
						devicesAct.setCensorStatus(CensorStatusEnum.WAIT.getCode());
						devicesActMapper.update(devicesAct);
						
						DevicesStatusEnum devicesStatus = DevicesStatusEnum.getByCode(devices.getDevicesStatus());
						if(devicesStatus == DevicesStatusEnum.WAIT_UPLOAD_VOUCHER) {
							devices.setDevicesStatus(DevicesStatusEnum.WAIT_ACTIVATE.getCode());
							devicesMapper.update(devices);
						}
					}catch(Exception e) {
						status.setRollbackOnly();
						throw e;
					}
					return null;
				}
			});
		}else {
			DevicesUsedCertQuery query = new DevicesUsedCertQuery();
			query.setDevicesActId(devicesUsedCert.getDevicesActId());
			DevicesUsedCert oldCert = devicesUsedCertMapper.selectInfoByQuery(query);
			if(oldCert == null) {
				throw new IllegalStateException("devicesUsedCert not exist");
			}
			
			transactionTemplate.execute(new TransactionCallbackWithoutResult() {
				
				@Override
				protected void doInTransactionWithoutResult(TransactionStatus status) {
					try {
						for(int i = 0 ; i < devicesUsedCert.getDevicesUsedCertUpfiles().size(); i++) {
							DevicesUsedCertUpfile upfile = devicesUsedCert.getDevicesUsedCertUpfiles().get(i);
							upfile.setDevicesUsedCertId(oldCert.getDevicesUsedCertId());
							upfile.setSequence(i + oldCert.getCertTotal());
							upfile.setCreateTime(new Date());
							devicesUsedCertUpfileMapper.insert(upfile);
						}
					}catch(Exception e) {
						status.setRollbackOnly();
						throw e;
					}
				}
			});
		}
	}

	@Override
	public void upcert(DevicesUsedCert cert) {
		
		
		if(cert == null) {
			throw new ParametersException("DevicesUsedCert is null");
		}
		
		if(cert.getDevicesActId() == null) {
			throw new ParametersException("DevicesActId is null");
		}
		
		if(cert.getUpfiles() == null || cert.getUpfiles().isEmpty()) {
			throw new ParametersException("文件未获取");
		}
		
		cert.setCertTotal(cert.getUpfiles().size());
		
		//DevicesUsed devicesUsed = devicesUsedMapper.selectInfoById(cert.getDevicesUsedId());
		
		DevicesAct devicesAct = devicesActMapper.selectInfoById(cert.getDevicesActId());
		
		if(devicesAct == null) {
			throw new ParametersException("授权记录不存在");
		}
		
//		if(!devicesAct.getUsedStatus().equals("WAIT_UPLOAD_CERT")) {
//			throw new ParametersException("您还未使用或使用凭证已上传");
//		}
		
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				try {
					
					List<Upfile> upfiles = cert.getUpfiles();
					
					if(upfiles != null && !upfiles.isEmpty()) {
						
						
						String fileurls = "";
						for(int i = 0 ; i < upfiles.size(); i++) {
							Upfile upfile = upfiles.get(i);
							if(i==0) {
								fileurls += upfile.getFileUrl();
							}else {
								fileurls = ","+upfile.getFileUrl();
							}
						}
						
						cert.setCertTotal(cert.getUpfiles().size());
						cert.setCompanyId(cert.getCompanyId());
						cert.setCertStatus(CertUploadStatusEnum.UPLOAD.code());
						cert.setCreateTime(new Date());
						cert.setFileurls(fileurls);
						devicesUsedCertMapper.insert(cert);
						
						
						for(int i = 0 ; i < upfiles.size(); i++) {
							
							Upfile upfile = upfiles.get(i);
							
							DevicesUsedCertUpfile certUpfile = new DevicesUsedCertUpfile();
							certUpfile.setSequence(i);
							certUpfile.setCreateTime(new Date());
							certUpfile.setDevicesUsedCertId(cert.getDevicesUsedCertId());
							certUpfile.setUpfileId(upfile.getUpfileId());
							certUpfile.setCreateTime(new Date());
							devicesUsedCertUpfileMapper.insert(certUpfile);
						}
						
//						devicesUsed.setCertUploadStatus(CertUploadStatusEnum.UPLOAD.code());
//						devicesUsed.setUsedStatus(UsedStatusEnum.SUCCESS.code());
//						devicesUsedMapper.update(devicesUsed);
						devicesAct.setUploadCertTime(new Date());
						devicesAct.setUsedStatus("SUCCESS");
						devicesActMapper.update(devicesAct);
						
						//如果是测试申请
						if(devicesAct.getApplyType().equals(ApplyTypeEnum.TEST_APPLY.code())) {
							Devices devices = devicesMapper.selectInfoById(devicesAct.getDevicesId());
							devices.setDevicesStatus(DevicesStatusEnum.WAIT_ACTIVATE.code());
							devices.setCertUrls(fileurls);
							devicesMapper.update(devices);
						}
					}
				}catch(Exception e) {
					status.setRollbackOnly();
					throw e;
				}
				
			}
		});
	}

	@Override
	public Devices getInfoByQuery(DevicesQuery query) {
		if(query == null) {
			throw new ParametersException("query is null");
		}
		
		Devices devices = devicesMapper.selectInfoByQuery(query);
		return devices;
	}

	@Override
	public void take(DevicesTake take, Long userPartyId) {
		if(take == null) {
			throw new ParametersException("take");
		}
		
		if(userPartyId == null) {
			throw new ParametersException("userPartyId");
		}
		
		if(take.getDevicesTakeId() == null) {
			throw new ParametersException("devicesTakeId");
		}
		
		if(take.getDevicesId() == null) {
			throw new ParametersException("devicesId");
		}
		
		DevicesTake oldTake = devicesTakeMapper.selectInfoById(take.getDevicesTakeId());
		
		if(oldTake == null) {
			throw new DataNotFoundException("take is not found");
		}
		
		TakeStatusEnum takeStatus = TakeStatusEnum.getByCode(oldTake.getTakeStatus());
		if(takeStatus != TakeStatusEnum.PENDING) {
			throw new ParametersException("待领取记录状态不是带领取");
		}
		
		Devices devices = devicesMapper.selectInfoById(take.getDevicesId());
		if(devices == null) {
			throw new DataNotFoundException("devices is not found");
		}
		
		DevicesTakeQuery takeQuery = new DevicesTakeQuery();
		takeQuery.setTakeStatus(TakeStatusEnum.WAIT_RETURN.getCode());
		takeQuery.setDevicesId(devices.getDevicesId());
		DevicesTake otherTake = devicesTakeMapper.selectInfoByQuery(takeQuery);
		if(otherTake != null && otherTake.getPartyId().equals(oldTake.getPartyId())) {
			renewalTake(devices, oldTake, takeQuery, otherTake);
		}else {
			normalTake(devices, oldTake, take, userPartyId);
		}
	}
	
	private void normalTake(Devices devices, DevicesTake oldTake, DevicesTake take, Long userPartyId) {
		assert devices != null;
		assert oldTake != null;
		assert take != null;
		assert userPartyId != null;
		
		TakeStatusEnum devicesTakeStatus = TakeStatusEnum.getByCode(devices.getTakeStatus());
		if(devicesTakeStatus != TakeStatusEnum.NORMAL) {
			throw new DataNotFoundException("设备的已被外借，不能再次借出");
		}
		
		Seal seal = sealMapper.selectInfoById(devices.getSealId());
		if(seal == null) {
			throw new DataNotFoundException("seal is not found");
		}
		
		if(!userPartyId.equals(seal.getPartyId()) && !userPartyId.equals(seal.getInterimPartyId())) {
			throw new IllegalAccessError("您无权进行此操作");
		}
		
		devices.setTakeStatus(TakeStatusEnum.WAIT_RETURN.getCode());
		
		oldTake.setTakeStatus(TakeStatusEnum.WAIT_RETURN.getCode());
		oldTake.setTakeTime(new Date());
		oldTake.setDevicesId(take.getDevicesId());
		
		List<Custos> custosRef = new ArrayList<Custos>();
		long currentTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN).toInstant(ZoneOffset.of("+8")).toEpochMilli();
		if(seal.getInterimPartyId() != null && 
				seal.getInterimExpiredDate() != null && 
				seal.getInterimExpiredDate().getTime() >= currentTime) {
			
			CustosQuery custosQuery = new CustosQuery();
			custosQuery.setPartyId(seal.getInterimPartyId());
			custosQuery.setCompanyId(seal.getCompanyId());
			custosQuery.setCustosStatus(CustosStatusEnum.EFFECTIVE.getCode());
			custosQuery.setCustosType(CustosTypeEnum.INTERIM.getCode());
			Custos custos = custosMapper.selectInfoByQuery(custosQuery);
			if(custos != null) {
				custos.setCustosStatus(CustosStatusEnum.TEMPORARY_INVALID.getCode());
				custos.setRemark("设备外带临时管理员临时失效");
				custosRef.add(custos);
			}
		}
		
		seal.setInterimPartyId(oldTake.getPartyId());
		seal.setInterimExpiredDate(oldTake.getEndDate());
		
		transactionTemplate.execute(new TransactionCallback<Boolean>() {
			
			@Override
			public Boolean doInTransaction(TransactionStatus status) {
				try {
					devicesTakeMapper.update(oldTake);
					devicesMapper.update(devices);
					sealMapper.updateInterim(seal);
					if(!custosRef.isEmpty() && custosRef.get(0) != null) {
						custosMapper.update(custosRef.get(0));
					}
				}catch(Exception e) {
					status.setRollbackOnly();
					throw e;
				}
				return null;
			}
		});
		
	}
	
	private void renewalTake(Devices devices, DevicesTake oldTake, DevicesTake take, DevicesTake otherTake) {
		assert devices != null;
		assert oldTake != null;
		assert take != null;
		assert otherTake != null;
		
		TakeStatusEnum devicesTakeStatus = TakeStatusEnum.getByCode(devices.getTakeStatus());
		if(devicesTakeStatus != TakeStatusEnum.WAIT_RETURN) {
			throw new DataNotFoundException("设备不是外借状态无法续期");
		}
		
		Seal seal = sealMapper.selectInfoById(devices.getSealId());
		if(seal == null) {
			throw new DataNotFoundException("seal is not found");
		}
		
		otherTake.setTakeStatus(TakeStatusEnum.RETURND.getCode());
		otherTake.setReturnTime(new Date());
		
		
		oldTake.setTakeStatus(TakeStatusEnum.WAIT_RETURN.getCode());
		oldTake.setTakeTime(new Date());
		oldTake.setDevicesId(take.getDevicesId());
		oldTake.setStartDate(otherTake.getStartDate());
		
		seal.setInterimPartyId(oldTake.getPartyId());
		seal.setInterimExpiredDate(otherTake.getEndDate());
		
		transactionTemplate.execute(new TransactionCallback<Boolean>() {
			
			@Override
			public Boolean doInTransaction(TransactionStatus status) {
				try {
					devicesTakeMapper.update(oldTake);
					devicesTakeMapper.update(otherTake);
					sealMapper.updateInterim(seal);
				}catch(Exception e) {
					status.setRollbackOnly();
					throw e;
				}
				return null;
			}
		});
		
	}
	
	@Override
	public void setInterim(Seal seal) {
		
		if(seal == null || seal.getSealId() == null) {
			throw new IllegalArgumentException("seal");
		}
		
		if(seal.getCompanyId() == null) {
			throw new IllegalArgumentException("seal.companyId");
		}
		
		if(seal.getInterimPartyId() == null) {
			throw new IllegalArgumentException("seal.interimPartyId");
		}

		
		if(seal.getInterimExpiredDate() == null) {
			throw new IllegalArgumentException("seal.interimExpiredDate");
		}
		
		Calendar nowDate = Calendar.getInstance();
		nowDate.setTime(seal.getInterimExpiredDate());
		nowDate.add(Calendar.DAY_OF_YEAR, 1);
		nowDate.add(Calendar.SECOND, -1);
		
		if(nowDate.getTimeInMillis() < System.currentTimeMillis()) {
			throw new IllegalArgumentException("seal.interimExpiredDate");
		}
		
		Party party = partyMapper.selectByPrimaryKey(seal.getInterimPartyId());
		
		Seal oldSeal = sealMapper.selectInfoById(seal.getSealId());
		if(oldSeal == null) {
			throw new IllegalStateException("seal not exist: sealId:" + seal.getSealId());
		}
		Devices devices = devicesMapper.selectInfoByQuery(new DevicesQuery(oldSeal.getSealId()));
		
		
		
		this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				try {
					
					oldSeal.setInterimPartyId(seal.getInterimPartyId());
					oldSeal.setInterimExpiredDate(seal.getInterimExpiredDate());
					sealMapper.update(oldSeal);
					
					
					Custos exist = custosMapper.selectInfoByQuery(new CustosQuery(oldSeal.getCompanyId(),oldSeal.getSealId(),oldSeal.getDevicesId(),CustosStatusEnum.EFFECTIVE.code(),CustosTypeEnum.INTERIM.code()));
					//判断保管员是否存在
					if(exist !=null) {
						//判断保管员是否有变化
						if(!seal.getInterimPartyId().equals(exist.getPartyId())) {
							exist.setCustosStatus(CustosStatusEnum.INVALID.code());
							exist.setRemark("保管员重置临时管理员失效");
							custosMapper.update(exist);
							
							Custos custos = new Custos();
							custos.setCustosType(CustosTypeEnum.INTERIM.code());
							custos.setCompanyId(seal.getCompanyId());
							custos.setSealId(seal.getSealId());
							custos.setPartyId(seal.getInterimPartyId());
							custos.setExpireData(seal.getInterimExpiredDate());
							custos.setUserLoginId(party.getUserLoginId());
							custos.setDevicesId(devices.getDevicesId());
							custos.setCreateTime(new Date());
							custos.setCustosStatus(CustosStatusEnum.EFFECTIVE.code());
							custos.setRemark("保管员设置临时管理员");
							custosMapper.insert(custos);
							
						}else {
							exist.setExpireData(seal.getInterimExpiredDate());
							custosMapper.update(exist);
						}
					}else {
						Custos custos = new Custos();
						custos.setCustosType(CustosTypeEnum.INTERIM.code());
						custos.setCompanyId(seal.getCompanyId());
						custos.setSealId(seal.getSealId());
						custos.setPartyId(seal.getInterimPartyId());
						custos.setExpireData(seal.getInterimExpiredDate());
						custos.setUserLoginId(party.getUserLoginId());
						custos.setCreateTime(new Date());
						custos.setDevicesId(devices.getDevicesId());
						custos.setCustosStatus(CustosStatusEnum.EFFECTIVE.code());
						custos.setRemark("保管员设置临时管理员");
						custosMapper.insert(custos);
					}
				}catch (Exception e) {
					logger.error("",e);
					status.setRollbackOnly();
					throw e;
				}
				
			}
		});
		
		
		
	}
	
	@Override
	public void releaseInterim(long sealId) {
		
		Seal seal = sealMapper.selectInfoById(sealId);
		DevicesQuery devicesQuery = new DevicesQuery();
		devicesQuery.setSealId(sealId);;
		Devices devices = devicesMapper.selectInfoByQuery(devicesQuery);
		if(seal == null || devices == null) {
			return ;
		}
		
		DevicesTakeQuery takeQuery = new DevicesTakeQuery();
		takeQuery.setDevicesId(devices.getDevicesId());
		takeQuery.setTakeStatus(TakeStatusEnum.WAIT_RETURN.getCode());
		DevicesTake take = devicesTakeMapper.selectInfoByQuery(takeQuery);
				
		if(take != null) {
			throw new IllegalStateException("印章处于外带状态，无法取消");
		}
		
		seal.setInterimPartyId(null);
		seal.setInterimExpiredDate(null);
		

		this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {

			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				sealMapper.updateInterim(seal);
				
				Custos custos = custosMapper.selectInfoByQuery(
						new CustosQuery(
								seal.getCompanyId(),
								seal.getSealId(),
								seal.getDevicesId(),
								CustosStatusEnum.EFFECTIVE.code(),
								CustosTypeEnum.INTERIM.code()));
				
				if(custos != null) {
					custos.setCustosStatus(CustosStatusEnum.INVALID.code());
					custos.setRemark("保管员清除临时管理员失效");
					custosMapper.update(custos);
				}
			}
		});
	}

	@Override
	public void setName(Seal seal) {
		if(seal == null) {
			throw new IllegalArgumentException("seal");
		}
		
		if(seal.getSealId() == null) {
			throw new IllegalArgumentException("seal.sealId");
		}
		
		if(StringUtils.isBlank(seal.getSealName())) {
			throw new ParametersException("印章名称不能为空");
		}
		
		Seal old = sealMapper.selectInfoById(seal.getSealId());
		if(old == null) {
			throw new IllegalStateException("印章不存在");
		}
		
		old.setSealName(seal.getSealName());
		sealMapper.update(old);
	}

	private boolean isCompanyAdmin(Long companyId, String userLoginId) {
		assert companyId != null;
		assert StringUtils.isNotBlank(userLoginId);
		
		Company company = companyMapper.selectInfoById(companyId);
		return company != null && userLoginId.equals(company.getUserLoginId());
	}
	
	private boolean isSealCustos(Long sealId, String userLoginId) {
		assert sealId != null;
		assert StringUtils.isNotBlank(userLoginId);
		
		Seal seal = sealMapper.selectInfoById(sealId);
		if(seal == null) {
			return false;
		}
		
		UserLogin userLogin = userLoginMapper.selectByUserLoginId(userLoginId);
		if(userLogin == null) {
			return false;
		}
		
		return seal.getPartyId().equals(userLogin.getPartyId());
		
	}

	@Override
	public void upgrade(Devices devices) {
		if(devices == null) {
			throw new IllegalArgumentException("devices");
		}
		
		if(devices.getDevicesId() == null) {
			throw new IllegalArgumentException("devices.devicesId");
		}
		
		if(StringUtils.isBlank(devices.getDevicesVerson())) {
			throw new IllegalArgumentException("devices.devicesVerson");
		}
		
		Devices old = devicesMapper.selectInfoById(devices.getDevicesId());
		if(old == null) {
			throw new IllegalStateException("devices not exist");
		}
		
		old.setDevicesVerson(devices.getDevicesVerson());
		devicesMapper.update(old);
	}

	@Override
	public void syncStatus(Devices devices) {
		
		if(devices == null) {
			throw new IllegalArgumentException("devices");
		}
		
		if(devices.getDevicesId() == null) {
			throw new IllegalArgumentException("devices.devicesId");
		}
		
		if(StringUtils.isBlank(devices.getDevicesStatus())) {
			throw new IllegalArgumentException("devices.devicesStatus");
		}
		
		Devices existDevices = devicesMapper.selectInfoById(devices.getDevicesId());
		if(existDevices == null || devices.getDevicesStatus().equals(existDevices.getDevicesStatus())) {
			return ;
		}
		
		if(DevicesStatusEnum.ACTIVATE.getCode().equals(devices.getDevicesStatus())) {
			InstallQuery installQuery = new InstallQuery();
			installQuery.setDevicesId(devices.getDevicesId());
			installQuery.setInstallStatus(InstallStatusEnum.PENDING.getCode());
			installQuery.setInstallType(InstallTypeEnum.AGAIN.getCode());
			Install install = installMapper.selectInfoByQuery(installQuery);
			if(install != null) {
				return ;
			}
		}
		
		existDevices.setDevicesStatus(devices.getDevicesStatus());
		devicesMapper.update(existDevices);
	}
}
